
import { Smoother } from "../Smoother";
import BaseEntity from "./BaseEntity";
import GameWorld from "./GameWorld";
import SteeringBehavior from "./SteeringBehaviors";

const { ccclass } = cc._decorator;
let tempVec2 = cc.v2();
let tempVec22 = cc.v2();
@ccclass
export default class Vehicle extends BaseEntity {
    //速度
    protected _velocity: cc.Vec2 = cc.v2();
    public get velocity(): cc.Vec2 {
        return this._velocity;
    }
    public set velocity(value: cc.Vec2) {
        this._velocity.set(value);
    }

    public static halfWidth = cc.winSize.width * 0.5;
    public static halfHeight = cc.winSize.height * 0.5;

    //朝向
    protected _heading: cc.Vec2 = cc.v2(0, 1);
    public get heading(): cc.Vec2 {
        return this._heading;
    }
    public set heading(value: cc.Vec2) {
        if (value.magSqr() < 0.00001) { console.error("new heading is zero", this.ID); return; }
        this._heading.set(value);
        Vehicle.Vec2Perp(this._side, this._heading);
        if (!this.isSmoother) {
            let angle = this._heading.signAngle(cc.Vec2.UP);
            let degress = cc.misc.radiansToDegrees(angle);
            if (this.node) {
                this.node.angle = -degress;
            }
        }
    }

    private _world: GameWorld = null;
    public get world(): GameWorld {
        return this._world;
    }
    public setWorld(value: GameWorld) {
        this._world = value;
    }

    //朝向的垂直方向向量
    protected _side: cc.Vec2 = cc.v2(-1, 0);
    public get side(): cc.Vec2 {
        return this._side;
    }
    public set side(value: cc.Vec2) {
        this._side = value;
    }

    //智能体最大速度值
    protected _maxSpeed: number = 150;
    public get maxSpeed(): number {
        return this._maxSpeed;
    }
    public set maxSpeed(value: number) {
        this._maxSpeed = value;
    }

    //智能体可以产生最大的驱动力
    protected _maxForce: number = 2*200;
    public get maxForce(): number {
        return this._maxForce;
    }
    public set maxForce(value: number) {
        this._maxForce = value;
    }

    //智能体可以产生的最大旋转力
    protected _maxTurnRate: number = Math.PI * 2;
    public get maxTurnRate(): number {
        return this._maxTurnRate;
    }
    public set maxTurnRate(value: number) {
        this._maxTurnRate = value;
    }

    protected _steering: SteeringBehavior = null;
    public get steering() {
        return this._steering;
    }


    protected _timeElapsed: number = 0;
    public timeElapse() {
        return this._timeElapsed;
    }

    public init(): void {
        super.init();
        if (!this._steering) {
            this._steering = new SteeringBehavior(this);
        }
        if (!this._headingSmoother) {
            this._headingSmoother = new Smoother(10);
        }
        Vehicle.halfWidth = cc.winSize.width * 0.5;
        Vehicle.halfHeight = cc.winSize.height * 0.5;
    }

    private _headingSmoother: Smoother = null;//多次采样来确定方向,防止频繁两头摆
    private _smootherHead: cc.Vec2 = cc.v2(0, 1);
    public get smootherHead(): cc.Vec2 {
        return this._smootherHead;
    }
    public set smootherHead(value: cc.Vec2) {
        this._smootherHead.set(value);
        let angle = this._smootherHead.signAngle(cc.Vec2.UP);
        let degress = cc.misc.radiansToDegrees(angle);
        if (this.node) {
            this.node.angle = -degress;
        }
    }
    public updateDir(dt: number) {
        this.smootherHead = this._headingSmoother.onUpdate(this._heading);
    }

    public isSmoother: boolean = true;
    private ischange:boolean = false;
    public update(dt: number): void {
        if (!this.isPause) {
            this._timeElapsed = dt;
        }
        this.ischange = false;
        let force = this.steering.calculate();
        cc.Vec2.multiplyScalar(tempVec2, force, dt);
        cc.Vec2.add(tempVec2, tempVec2, this.velocity);
        Vehicle.Vec2Truncate(tempVec2, this.maxSpeed);
        this.velocity = tempVec2;
        cc.Vec2.multiplyScalar(tempVec2, this.velocity, dt);
        cc.Vec2.set(tempVec22, this.node.x, this.node.y);
        cc.Vec2.add(tempVec2, tempVec22, tempVec2);
        this.node.setPosition(tempVec2);
        if (this.velocity.magSqr() > 0.0001) {
            cc.Vec2.normalize(tempVec2, this.velocity);
            this.heading = tempVec2;
        }
        if (this.isSmoother)
            this.updateDir(dt);
        if (this.node.x > Vehicle.halfWidth) {
            this.node.x = -Vehicle.halfWidth + this.node.x - Vehicle.halfWidth;
            this.ischange = true;
        }
        if (this.node.x < -Vehicle.halfWidth) {
            this.node.x = Vehicle.halfWidth + this.node.x + Vehicle.halfWidth;
            this.ischange = true;
        }
        if (this.node.y > Vehicle.halfHeight) {
            this.node.y = -Vehicle.halfHeight + this.node.y - Vehicle.halfHeight;

            this.ischange = true;
        }
        if (this.node.y < -Vehicle.halfHeight) {
            this.node.y = Vehicle.halfHeight + this.node.y + Vehicle.halfHeight;
            this.ischange = true;
        }
    }
    public static Vec2Perp(out: cc.Vec2, a: cc.Vec2) {
        cc.Vec2.set(out, -a.y, a.x);
        return out;
    }

    public static Vec2Truncate(out: cc.Vec2, max: number) {
        if (max <= 0) return cc.Vec2.ZERO;
        if (out.magSqr() > max * max) {
            cc.Vec2.normalize(out, out);
            cc.Vec2.multiplyScalar(out, out, max);
        }
        return out;
    }
}
